/**
 * @brief Biblioteca de álgebra de vetores
 *
 * @author Thales Luis Rodrigues Sabino
 * @date   2009
 */

#include "mcMath.h"

using namespace mc;

/**
 * @brief Construtor padrão. Constroi um vetor com o valor t
 *
 * @param t - Valor para ser setado em todas as componentes
 */
template <class T>
vec4<T>::vec4( const T &t ) {
    this->x = t;
    this->y = t;
    this->z = t;
    this->w = t;
}

/**
* @brief Constrói a partir de um array
*
* @param a - Array para construir o vetor
*/
template <class T>
vec4<T>::vec4( const T *a ) {
    this->x = a[0];
    this->y = a[1];
    this->z = a[2];
    this->w = a[3];
}

/**
 * @brief Constrói um vetor explicitamente
 *
 * @param x - Compomente X
 * @param y - Componente Y
 */
template <class T>
vec4<T>::vec4( const T x, const T y, const T z, const T w ) {
    this->x = x;
    this->y = y;
    this->z = z;
    this->w = w;
}

/**
 * @brief Constrói por cópia
 *
 * @param v - Vetor a ser copiado
 */
template <class T>
vec4<T>::vec4( vec2<T> &v ) {
    this->x = v.x;
    this->y = v.y;
    this->z = T (0);
    this->w = T (0);
}


/**
 * @brief Constrói por cópia
 *
 * @param v - Vetor a ser copiado
 */
template <class T>
vec4<T>::vec4( vec3<T> &v ) {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
    this->w = T (0);
}


/**
 * @brief Constrói por cópia
 *
 * @param v - Vetor a ser copiado
 */
template <class T>
vec4<T>::vec4( vec4<T> &v ) {
    this->x = v.x;
    this->y = v.y;
    this->z = v.z;
    this->w = v.w;
}


/**
 * @brief Operador [] para acesso ao vetor
 *
 * @param i - Índice de acesso
 */
template <class T>
T& vec4<T>::operator [] ( int i ) {
    /// Teste de índice
    assert( i >= 0 && i < this->size() );
    return _array[i];
}


/**
 * @brief Operador soma de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec4<T>& vec4<T>::operator + ( const vec4<T> &v ) {
    vec4<T> *vr = new vec4<T>();
    vr->x = this->x + v.x;
    vr->y = this->y + v.y;
    vr->z = this->z + v.z;
    vr->w = this->w + v.w;
    return *vr;
}


/**
 * @brief Operador subtração de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec4<T>& vec4<T>::operator - ( const vec4<T> &v ) {
    vec4<T> *vr = new vec4<T>();
    vr.x = this->x - vr.x;
    vr.y = this->y - vr.y;
    vr.z = this->z - vr.z;
    vr.w = this->w - vr.w;
    return *vr;
}


/**
 * @brief Operador multiplicação das componentes de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec4<T>& vec4<T>::operator * ( const vec4<T> &v ) {
    vec4<T> *vr = new vec4<T>();
    vr.x = this->x * v.x;
    vr.y = this->y * v.y;
    vr.z = this->z * v.z;
    vr.w = this->w * v.w;
    return *vr;
}


/**
 * @brief Operador divisão de compomentes de dois vetores
 *
 * @param v1
 * @param v2
 */
template <class T>
vec4<T>& vec4<T>::operator / ( const vec4<T> &v ) {
    vec4<T> *vr = new vec4<T>();
    vr.x = this->x / v.x;
    vr.y = this->y / v.y;
    vr.z = this->z / v.z;
    vr.w = this->w / v.w;
    return *vr;
}


/**
 * @brief Operador de escalamento
 *
 * @param v - Vetor a ser escalado
 * @param s - Fator de escala
 */
template <class T>
vec4<T>& vec4<T>::operator * ( const T s ) {
    vec4<T> *vr = new vec4<T>();
    vr.x = this->x * s;
    vr.y = this->y * s;
    vr.z = this->z * s;
    vr.w = this->w * s;
    return *vr;
}



/**
 * @brief Operador de escalamento
 *
 * @param v - Vetor a ser escalado
 * @param s - Fator de escala
 */
template <class T>
vec4<T>& vec4<T>::operator / ( const T s ) {
    vec4<T> *vr = new vec4<T>();
    vr->x = this->x / s;
    vr->y = this->y / s;
    vr->z = this->z / s;
    vr->w = this->w / s;
    return *vr;
}


/**
 * @brief Acumulador +=
 *
 * @param v
 */
template <class T>
vec4<T>& vec4<T>::operator += ( const vec4<T> &v ) {
    this->x += v.x;
    this->y += v.y;
    this->z += v.z;
    this->w += v.w;
    return *this;
}


/**
 * @brief Acumulador -=
 *
 * @param v
 */
template <class T>
vec4<T>& vec4<T>::operator -= ( const vec4<T> &v ) {
    this->x -= v.x;
    this->y -= v.y;
    this->z -= v.z;
    this->w -= v.w;
    return *this;
}


/**
 * @brief Acumulador *=
 *
 * @param v
 */
template <class T>
vec4<T>& vec4<T>::operator *= ( const vec4<T> &v ) {
    this->x *= v.x;
    this->y *= v.y;
    this->z *= v.z;
    this->w *= v.w;
    return *this;
}


/**
 * @brief Acumulador /=
 *
 * @param v
 */
template <class T>
vec4<T>& vec4<T>::operator /= ( const vec4<T> &v ) {
    this->x /= v.x;
    this->y /= v.y;
    this->z /= v.z;
    this->w /= v.w;
    return *this;
}

